/*
 * Copyright (C) 2016 FarmFriend Co., Ltd. All rights reserved.
 */

package com.tsingteng.cosfun.crashUtils.log;


import android.content.pm.PackageInfo;

import com.tsingteng.cosfun.app.AppContext;
import com.tsingteng.cosfun.utils.AppUtils;
import com.tsingteng.cosfun.utils.LogonUtils;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BugReporter {

    private static final String TAG = "BugReporter";
    private static BugReporter sInstance;
    private static final long TASK_EXPIRE_TIME_IN_MILLISECONDS = 10 * 60 * 1000L;
    private final List<ReportTask> mReportTasks; // report-tasks currently running
    private static ExecutorService sThreadPools;

    public interface BugReporterListener {

        void reportDone(final boolean succeed);
    }

    /**
     * @return BugReporter 实例.
     */
    public static synchronized BugReporter getInstance() {
        if (null == sInstance) {
            sInstance = new BugReporter();
            sThreadPools = Executors.newSingleThreadExecutor();
        }
        return sInstance;
    }

    /**
     * @param taskId   任务ID
     * @param listener 监听.
     */
    public void report(final String taskId, final BugReporterListener listener) {
        dropExpiredTasks();
        if (isTaskRunning(taskId)) {
            return;
        }

        final ReportTask task = new ReportTask(taskId);
        String loginUserId = "unknown";
        try {
            loginUserId  = "id"+ LogonUtils.getProFildId();
        } catch (Exception ignored) {
            ignored.fillInStackTrace();
        }
        AppUtils.setHaveException(FileLogger.getErrorLogger().getFilePath()
                + "," + FileLogger.getActionLogger().getFilePath());

        final String loginUserIdFinal = loginUserId;
        task.mThread = new Thread(new Runnable() {
            @Override
            public void run() {
                doReport(loginUserIdFinal,
                        succeed -> {
                            removeTask(taskId);
                            if (listener != null) {
                                listener.reportDone(succeed);
                            }
                        });
            }
        });
        sThreadPools.execute(task.mThread);
        addTask(task);
    }

    private static class ReportTask {

        String mTaskId;
        long mStartTime; // in milliseconds
        Thread mThread;

        ReportTask(String taskId) {
            this.mTaskId = taskId;
            mStartTime = System.currentTimeMillis();
        }
    }

    private BugReporter() {
        mReportTasks = new ArrayList<>();
    }

    private synchronized void dropExpiredTasks() {
        List<ReportTask> expiredTasks = new ArrayList<>();
        for (ReportTask task : mReportTasks) {
            if (System.currentTimeMillis() - task.mStartTime > TASK_EXPIRE_TIME_IN_MILLISECONDS) {
                expiredTasks.add(task);
            }
        }
        mReportTasks.removeAll(expiredTasks);
    }

    private synchronized boolean isTaskRunning(String taskId) {
        for (ReportTask task : mReportTasks) {
            if (task.mTaskId.equals(taskId)) {
                return true;
            }
        }
        return false;
    }

    private synchronized void removeTask(String taskId) {
        ReportTask matchTask = null;

        for (ReportTask task : mReportTasks) {
            if (task.mTaskId.equals(taskId)) {
                matchTask = task;
            }
        }

        if (matchTask != null) {
            mReportTasks.remove(matchTask);
        }
    }

    private synchronized void addTask(ReportTask task) {
        mReportTasks.add(task);
    }

    private void doReport(String loginAccount, final BugReporterListener listener) {
        // record apps installed into error log file
        try {
            List<PackageInfo> packages = AppContext.getContext()
                .getPackageManager().getInstalledPackages(0);
            StringBuilder sb = new StringBuilder("apps installed \n");
            for (PackageInfo packageInfo : packages) {
                sb.append("packageName ");
                sb.append(packageInfo.packageName);
                sb.append(", versionCode ");
                sb.append(packageInfo.versionCode);
                sb.append(", versionName ");
                sb.append(packageInfo.versionName);
                sb.append(", firstInstallTime ");
                sb.append(packageInfo.firstInstallTime);
                sb.append(", lastUpdateTime ");
                sb.append(packageInfo.lastUpdateTime);
                sb.append("\n");
            }
            FileLogger.getErrorLogger().write(sb.toString());
        } catch (Throwable ignored) {
            ignored.printStackTrace();
        }
    }
}
